using System;
using System.Collections.Generic;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.GamePlay;
using LFloatMath.Math;
using NetProtocol.POD;
using Random = LFloatMath.Math.Random;

namespace IQIGame.Onigao.Logic
{
    public class Unit : TEntity, IFormulaObject, IPODFactory
    {
        public LFloat[] backstabRange = new LFloat[4]; // 背刺判定范围(弧度) 左(逆时针)右正侧左右侧后

        public Battle battle;
        public LVector2 bornPos;

        public int configID;
        public int GUID;
        public int lv = 10;

        private List<LVector2Int> mapHold = new List<LVector2Int>();
        public int maxWeaknessPoint;
        private LVector2 mForward = LVector2.zero; // 朝向，已归一化

        protected LVector2 mPos = LVector2.zero;
        private int mWeaknessPoint;
        public LFloat radius;
        public int skinID;

        private readonly BattleUnitStatistics _statistics = new();
        // 战斗总结数据
        public virtual BattleUnitStatistics statistics => this._statistics;

        public List<Unit> summon = new List<Unit>();
        public int teamIndex;
        public BattleUnitPOD unitPOD;
        public EUnitType unitType;
        public int weaknessBreakRound = -1;

        public EDamageType weaknessType; // 弱点 复合枚举

        public int weaknessPoint
        {
            get => this.mWeaknessPoint;
            set
            {
                this.mWeaknessPoint = Math.Clamp(value, 0, this.maxWeaknessPoint);

                var rResultCtrl = this.battle?.playCtrl?.resultCtrl;
                if (rResultCtrl != null)
                {
                    rResultCtrl.Add(BattleUpdateFactory.CreateUnitWeaknessPoint(this.GUID, this.mWeaknessPoint));
                }
            }
        }

        public LVector2 pos => this.mPos;
        public LVector2 forward => this.mForward;

        public virtual IPOD GeneratePOD()
        {
            var rPOD = new BattleUnitViewPOD()
            {
                guid = this.GUID,
                configID = this.configID,
                unitType = (int)this.unitType,
                level = this.lv,
                pos = this.mPos.ToPOD(),
                forward = this.mForward.ToPOD(),
                weaknessPoint = this.maxWeaknessPoint,
                weaknessType = (int)this.weaknessType,
                skinID = this.skinID,
            };
            var rAttrList = new List<int>();
            var rAttrComp = this.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
            for (int i = (int)EAttributeType.Min; i < (int)EAttributeType.Max; i++)
            {
                var rType = (EAttributeType)i;
                if (rType == EAttributeType.Hp || rType == EAttributeType.SP)
                {
                    rAttrList.Add(rAttrComp.Get(rType));
                }
                else
                {
                    rAttrList.Add(rAttrComp.GetPanel(rType));
                }
            }
            rPOD.unsafe_attr = rAttrList;
            var rSkillList = new List<int>();
            var rSkillComp = this.GetComponent<SkillComponent>(ETComponentType.SkillComponent);
            for (int i = 0; i < rSkillComp.skills.Count; i++)
            {
                rSkillList.Add(rSkillComp.skills[i].skillID);
            }
            rPOD.unsafe_skill = rSkillList;
            var rPetComponent = this.GetComponent<PetComponent>(ETComponentType.PetComponent);
            rPOD.pet = rPetComponent.petID;
            return rPOD;
        }

        public virtual void SetPos(LVector2 rNewPos, LVector2 rForward, List<LVector2> path = null, bool checkMoveRange = true)
        {
            // 先设置朝向 
            bool bDirty = false;

            var rOld = this.mPos;

            if (rForward != LVector2.zero)
            {
                bDirty = this.mForward != rForward;
                this.mForward = rForward.normalized;
            }
            else if (path != null && path.Count > 0)
            {
                var rPos1 = path[^1];
                var rPos2 = path.Count > 1 ? path[^2] : rOld;
                var rAsp = (rPos1 - rPos2).normalized;
                if (rAsp != LVector2.zero)
                {
                    bDirty = this.mForward != rForward;
                    this.mForward = rAsp;
                }
            }

            // 后设置位置，如果位置不变就跳过位置设置，直接传递给表现层
            if (rNewPos == LVector2.zero || this.mPos != rNewPos)
            {
                bDirty = true;
                if (checkMoveRange)
                {
                    // 判断下移动范围
                    // 角色移动范围
                    var fMoveRange = this.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent).Get(EAttributeType.MoveRange) / LFloat.thousand;
                    var rDis = rNewPos - rOld;
                    rDis = LVector2.ClampMagnitude(rDis, fMoveRange);
                    rNewPos = rOld + rDis;
                }
                // 地图范围
                rNewPos = LVector2.ClampMagnitude(rNewPos, this.battle.playCtrl.mapCtrl.radius);

                this.mPos = rNewPos;
                var rColComp = this.GetComponent<CollisionComponent>(ETComponentType.CollisionComponent);
                if (rColComp != null && rColComp.proxy != null)
                {
                    rColComp.proxy.pos = this.mPos;
                }
                // 地图占位
                var rMapCtrl = this.battle?.playCtrl?.mapCtrl;
                if (rMapCtrl != null)
                {
                    // 清理旧的
                    this.ClearHoldMap();
                    rMapCtrl.SetObstruct(this.mPos, this.radius, ref this.mapHold, this.GUID);
                }
            }

            if (bDirty)
            {
                var rResultCtrl = this.battle?.playCtrl?.resultCtrl;
                if (rResultCtrl != null)
                {
                    rResultCtrl.Add(BattleUpdateFactory.CreateUnitPosChange(this.GUID, this.mPos, this.forward, path));
                }
            }
        }

        public void ClearHoldMap()
        {
            var rMapCtrl = this.battle?.playCtrl?.mapCtrl;
            var rAllUnits = this.battle?.playCtrl?.unitCtrl.units;
            if (rMapCtrl == null || rAllUnits == null)
            {
                return;
            }

            // 清理旧的
            for (int i = 0; i < this.mapHold.Count; i++)
            {
                var rOldMap = this.mapHold[i]; // 倒叙循环
                // 查一下此地图是否在其他单位的占位内
                bool bIn = false;
                for (int j = 0; j < rAllUnits.Count; j++)
                {
                    var rUnit = rAllUnits[j];
                    if (rUnit != this && !rUnit.IsDead() && rUnit.mapHold.Contains(rOldMap))
                    {
                        bIn = true;
                        break;
                    }
                }

                if (!bIn)
                {
                    rMapCtrl.SetMapNodeObstruct(rOldMap, BattleMapController.EObstructType.Role, false, this.GUID);
                }
            }
            this.mapHold.Clear();
        }

        protected override void OnDispose()
        {
            this.ClearHoldMap();
            this.battle = null;
            this.unitPOD = null;
        }

        /// <summary>
        /// </summary>
        /// <param name="fakeDead">是否包含假死</param>
        /// <param name="realDead">是否包含真死</param>
        /// <returns></returns>
        public bool IsDead(bool fakeDead = false, bool realDead = true)
        {
            var rDeadComp = this.GetComponent<DeadComponent>(ETComponentType.DeadComponent);
            // 先检查 rDeadComp 是否为 null
            if (rDeadComp == null)
            {
                return false;
            }
            // 根据 fakeDead 和 realDead 的不同组合进行判断
            return (fakeDead && (realDead || !rDeadComp.realDead)) || (!fakeDead && realDead && rDeadComp.realDead);
        }

        public bool CheckDead()
        {
            var rAttr = this.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
            return rAttr != null && rAttr.Get(EAttributeType.Hp) <= 0;
        }

        public bool IsTotem() => this.unitType == EUnitType.Totem;
        
        /// <summary>
        ///     检测背刺 传入的方向由受击者为起点
        /// </summary>
        /// <param name="aspect"></param>
        /// <returns></returns>
        public EBackstabType CheckBackstab(LVector2 aspect)
        {
            var rSelf = this.forward;
            if (rSelf == LVector2.zero)
            {
                rSelf = LVector2.right;
            }
            // 计算 rself 与aspect 夹角的cos值
            var fCos = LVector2.Dot(rSelf, aspect.normalized);
            var bLeft = LVector2.Cross(rSelf, aspect) >= 0;
            var fRange = bLeft ? this.backstabRange[0] : this.backstabRange[1];
            if (fRange > 0 && LMath.Cos(fRange) < fCos)
            {
                return EBackstabType.Front;
            }
            fRange = bLeft ? this.backstabRange[2] : this.backstabRange[3];
            if (fRange > 0 && LMath.Cos(fRange) < fCos)
            {
                return EBackstabType.Flank;
            }
            return EBackstabType.Back;
        }

        public virtual void OnRoundStart()
        {
            var rSkillComp = this.GetComponent<SkillComponent>(ETComponentType.SkillComponent);
            rSkillComp.OnRoundStart();
            var rBuffComp = this.GetComponent<BuffComponent>(ETComponentType.BuffComponent);
            rBuffComp.OnDot(EBuffDotTriggerType.RoundStart);

            if (this.maxWeaknessPoint > 0 && this.weaknessPoint <= 0 && !this.InWeaknessBreak())
            {
                this.weaknessPoint = this.maxWeaknessPoint;
            }
            var rAttrComp = this.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
            rAttrComp.RecoverSP(BattleConst.RoundStartSpRecover);
        }

        public virtual void OnRoundEnd()
        {
            var rBuffComp = this.GetComponent<BuffComponent>(ETComponentType.BuffComponent);
            rBuffComp.OnDot(EBuffDotTriggerType.RoundEnd);
            rBuffComp.OnRefresh();
        }

        public bool InWeaknessBreak()
        {
            return this.weaknessBreakRound >= 0 && this.battle.playCtrl.realRound - this.weaknessBreakRound < BattleConst.WeaknessBreakRound;
        }

        public void WeaknessBreak(Unit rAttacker, EDamageType rDamageType)
        {
            this.weaknessBreakRound = this.battle.playCtrl.realRound;

            if (this.battle.playCtrl.teamCtrl.teams.TryGetValue(rAttacker.teamIndex, out var rTeam))
            {
                for (int i = 0; i < rTeam.units.Count; i++)
                {
                    var rUnit = rTeam.units[i];
                    var rAttrComp = rUnit.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
                    rAttrComp.RecoverSP(BattleConst.WeaknessBreakSpRecover * this.maxWeaknessPoint);
                }
            }
        }

        public void AddStatDamage(int damage)
        {
            this.statistics.damage += damage;
        }

        public void AddStatCure(int cure)
        {
            this.statistics.cure += cure;
        }

        public void AddStatHurt(int hurt)
        {
            this.statistics.hurt += hurt;
        }

        public BattleUnitPOD ToUnitPOD()
        {
            if (this.unitPOD != null)
            {
                // 只传HP和SP
                var rAttrComp = this.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
                for (int i = 0; i < this.unitPOD.attrs.Length; i++)
                {
                    var rType = (EAttributeType)i;
                    switch (rType)
                    {
                        case EAttributeType.Hp:
                        case EAttributeType.SP:
                            this.unitPOD.attrs[i] = rAttrComp.Get(rType).ToInt();
                            break;
                        default:
                            this.unitPOD.attrs[i] = 0;
                            break;
                    }
                }
            }
            return this.unitPOD;
        }

#region Formula Func

        public virtual AttributeProperty GetAttr()
        {
            return this.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent).attr;
        }

        public Random GetBattleRandom()
        {
            return this.battle.random;
        }

        public IEnumerable<IFormulaObject> GetUnits(int nTeamIndex)
        {
            if (nTeamIndex < 0)
            {
                return this.battle.playCtrl.unitCtrl.units;
            }
            else
            {
                if (this.battle.playCtrl.teamCtrl.teams.TryGetValue(nTeamIndex, out var rTeam))
                {
                    return rTeam.units;
                }
            }
            return null;
        }

        public int GetTeamIndex() => this.teamIndex;

        public virtual int GetBuffStack(int buffID)
        {
            var nStack = 0;
            var rBuffComp = this.GetComponent<BuffComponent>(ETComponentType.BuffComponent);
            for (int i = 0; i < rBuffComp.buffList.Count; i++)
            {
                var rBuff = rBuffComp.buffList[i];
                if (rBuff.buffID == buffID)
                {
                    nStack = rBuff.stack;
                    break;
                }
            }
            return nStack;
        }

        public virtual T GetCustomProperty<T>(ECustomProperty propertyType)
        {
            return this.GetComponent<CustomPropertyComponent>(ETComponentType.CustomPropertyComponent).GetProperty<T>(propertyType);
        }

        public LVector2 GetPos() => this.pos;

#endregion
    }
}